package com.poem.aspect;

import com.poem.annotation.AutoFill;
import com.poem.constant.AutoFillConstant;
import com.poem.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @ClassName: AutoFillAspect
 * @Author: YLY
 * @Description:
 * @Date: 2025/10/26
 * @Version: 1.0
 */
@Slf4j
@Aspect
@Component
public class AutoFillAspect {

    /**
     * 切入点定义：
     * 抽取公共的切入点表达式
     * 拦截mapper包下的所有方法并且带有AutoFill注解
     */
    @Pointcut("execution(* com.poem.mapper.*..*(..)) && @annotation(com.poem.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    /**
     * 在目标方法前置执行，
     * 通过JoinPoint 获取方法信息和参数
     * 
     * @param joinPoint
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行数据填充");

        // 获取当前被拦截的方法上面的数据库的操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        OperationType operationType = autoFill.value();

        // 获取当前被拦截的方法参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            log.warn("方法参数为空，无法进行数据填充");
            return;
        }

        // 获取当前被拦截的方法参数中的第一个参数
        Object entity = args[0];

        if (entity == null) {
            log.warn("实体对象为空，无法进行数据填充");
            return;
        }

        // 准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        // Long currentId = BaseContext.getCurrentId();

        // 通过当前不同的数据库操作类型，为对应的属性通过反射来赋值
        if (operationType == OperationType.INSERT) {
            try {
                // 使用 getMethod 可以获取继承的方法
                Method setCreateTime = entity.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME,
                        LocalDateTime.class);
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME,
                        LocalDateTime.class);

                // 通过反射为对应的属性赋值
                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);

                log.info("插入操作：已填充创建时间和更新时间");

            } catch (Exception e) {
                log.error("插入操作：填充公共字段时发生异常", e);
            }
        } else if (operationType == OperationType.UPDATE) {
            try {
                // 使用 getMethod 可以获取继承的方法
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME,
                        LocalDateTime.class);
                // 通过反射为对应的属性赋值
                setUpdateTime.invoke(entity, now);

                log.info("更新操作：已填充更新时间");
            } catch (Exception e) {
                log.error("更新操作：填充公共字段时发生异常", e);
            }
        }
    }

}
